package com.dingding.nettyserver.core.server;

import com.dingding.nettyserver.common.trasferrule.request.Request;
import com.dingding.nettyserver.common.trasferrule.response.HandlerResult;
import com.dingding.nettyserver.common.trasferrule.response.Response;
import com.dingding.nettyserver.common.trasferrule.response.ResultCode;
import com.dingding.nettyserver.core.scanner.Invoker;
import com.dingding.nettyserver.core.scanner.InvokerHoler;
import com.dingding.nettyserver.core.session.Session;
import com.dingding.nettyserver.core.session.SessionImpl;
import com.dingding.nettyserver.core.session.SessionManager;
import com.dingding.nettyserver.core.util.LogKit;
import com.dingding.nettyserver.core.util.SessionKit;
import com.google.protobuf.MessageLite;

import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;

/**
 * @Description 服务器端与客户端交互的主类，用于事件处理和收发数据包等
 * @author fengshuonan
 * @date 2016年11月18日 下午9:44:51
 */
public class ServerHandler extends SimpleChannelInboundHandler<Request> {

	/**
	 * @Description 服务器对空闲读写的事件
	 * @author fengshuonan
	 */
	@Override
	public void userEventTriggered(final ChannelHandlerContext ctx, Object evt) throws Exception {

		if (evt instanceof IdleStateEvent) {
			IdleStateEvent event = (IdleStateEvent) evt;
			if (event.state() == IdleState.ALL_IDLE) {
				ChannelFuture writeAndFlush = ctx.writeAndFlush("ALL_IDLE  you will close");
				writeAndFlush.addListener(new ChannelFutureListener() {
					@Override
					public void operationComplete(ChannelFuture future) throws Exception {
						ctx.channel().close();
					}
				});
			} else if (event.state() == IdleState.WRITER_IDLE) {
				ChannelFuture writeAndFlush = ctx.writeAndFlush("WRITER_IDLE you will close");
				writeAndFlush.addListener(new ChannelFutureListener() {
					@Override
					public void operationComplete(ChannelFuture future) throws Exception {
						ctx.channel().close();
					}
				});
			} else if (event.state() == IdleState.READER_IDLE) {
				ChannelFuture writeAndFlush = ctx.writeAndFlush("READER_IDLE you will close");
				writeAndFlush.addListener(new ChannelFutureListener() {
					@Override
					public void operationComplete(ChannelFuture future) throws Exception {
						ctx.channel().close();
					}
				});
			}
		} else {
			super.userEventTriggered(ctx, evt);
		}
	}

	/**
	 * @Description 接收消息的处理
	 * @author fengshuonan
	 */
	@Override
	public void channelRead0(ChannelHandlerContext ctx, Request request) throws Exception {
		LogKit.reportBegin(SessionKit.ip(ctx));
		handlerMessage(new SessionImpl(ctx.channel()), request);
		LogKit.reportEnd(SessionKit.ip(ctx));
	}

	/**
	 * @Description 具体消息处理
	 * @author fengshuonan
	 */
	private void handlerMessage(Session session, Request request) {

		Response response = new Response(request);
		
		LogKit.info(
				"请求类型号:" + request.getBizType() + 
				",请求模块号是:" + request.getModule() + 
				",请求的命令号是:" + request.getCmd());

		// 获取命令执行器
		Invoker invoker = InvokerHoler.getInvoker(request.getBizType(), request.getModule(), request.getCmd());

		// 如果没有改命令的执行器
		if (invoker == null) {
			LogKit.info("找不到对应的命令执行器");
			response.setErrorData(ResultCode.NO_INVOKER);
			session.write(response);
			return;
		}

		try {
			// 初始化业务的返回数据
			HandlerResult<?> result = null;

			/**
			 * 判断这个命令是否需要登录这个前提
			 * 
			 * 如果需要登录，则先判断当前session有没有登录，再执行命令
			 * 
			 * 如果不需要登录，则直接执行业务命令
			 */
			if (!invoker.isRequiredLogin()) {
				result = (HandlerResult<?>) invoker.invoke(session, request.getData());
			} else {
				// 判断有没有登录
				Object attachment = session.getAttachment();
				if (attachment != null) {
					result = (HandlerResult<?>) invoker.invoke(session, request.getData());
				} else {
					// 会话未登录拒绝请求
					LogKit.info("会话未登录");
					response.setErrorData(ResultCode.NOT_LOGIN);
					session.write(response);
					return;
				}
			}

			// 判断请求是否业务执行成功
			if (result.getResultCode() == ResultCode.SUCCESS.getCode()) {
				Object object = result.getContent();
				if (object != null) {
					if (object instanceof MessageLite) {
						MessageLite content = (MessageLite) object;
						response.setData(content.toByteArray());
					} else {
						LogKit.info(String.format("不可识别传输对象:%s", object));
					}
				}
				session.write(response);
			} else {
				LogKit.error("业务执行异常！");
				response.setStateCode(result.getResultCode());
				response.setErrorData(ResultCode.UNKOWN_EXCEPTION);
				session.write(response);
				return;
			}
		} catch (Throwable e) {
			LogKit.error("业务执行异常！",e);
			response.setErrorData(ResultCode.UNKOWN_EXCEPTION);
			session.write(response);
		}
		
		LogKit.info("返回客户端信息,状态码为：" + ResultCode.messageOf(response.getStateCode())); 
		LogKit.info("返回的业务内容为：" + response.toString());
	}

	/**
	 * @Description 客户端断开连接时
	 * @author fengshuonan
	 */
	@Override
	public void channelInactive(ChannelHandlerContext ctx) throws Exception {
		Session session = new SessionImpl(ctx.channel());
		Object object = session.getAttachment();
		if (object != null) {
			String userId = (String) object;
			SessionManager.removeSession(userId);
		}
	}

	/**
	 * @Description 有新接入客户端时
	 * @author fengshuonan
	 */
	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		LogKit.info("新用户接入！用户ip地址是：" + SessionKit.ip(ctx));
	}

}
